package purchase

import (
	"LogisticsPort/model"
	"LogisticsPort/sql"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"math"
	"sort"
	"strings"
	"time"
)

/**
商品采购
*/

func Product(r *gin.RouterGroup) {
	product := r.Group("/product")
	{
		product.POST(sql.RequestAdd, purchaseProductAdd)
		product.POST(sql.RequestUpdate, purchaseProductUpdate)
		product.GET(sql.RequestDelete, purchaseProductDelete)
		product.GET(sql.RequestList, purchaseProductList)
		product.GET(sql.RequestData, purchaseProductData)
		product.POST(sql.RequestModify, purchaseModify)
		product.GET("/estimate/list", purchaseProductEstimateList)
	}
}

func purchaseProductAdd(c *gin.Context) {
	sql.HttpHandle(sql.ADD, c, func(db *gorm.DB) (*gorm.DB, interface{}) {
		var bean model.PurchaseProductEdit
		if err := c.Bind(&bean); err != nil {
			fmt.Println("bind params Err:", err)
			db.Error = errors.New(sql.ErrorParams)
			return db, nil
		}
		bean.InventoryNumber = bean.ProductNumber
		bean.InventoryWeight = bean.ProductWeight
		db = db.Table("purchase_product").Create(&bean)
		return db, bean
	})
}

func purchaseProductUpdate(c *gin.Context) {
	sql.HttpHandle(sql.ADD, c, func(db *gorm.DB) (*gorm.DB, interface{}) {
		var bean model.PurchaseProductEdit
		if err := c.Bind(&bean); err != nil {
			fmt.Println("bind params Err:", err)
			db.Error = errors.New(sql.ErrorParams)
			return db, nil
		}
		bean.InventoryNumber = bean.ProductNumber
		bean.InventoryWeight = bean.ProductWeight
		db = db.Table("purchase_product").Updates(&bean)
		return db, bean
	})
}

func purchaseProductData(c *gin.Context) {
	sql.HttpHandle(sql.GET, c, func(db *gorm.DB) (*gorm.DB, interface{}) {
		id := c.Query("id")
		var bean model.PurchaseProduct
		db = db.Model(&bean).
			Where("purchase_product.id = ?", id).
			Select("purchase_product.*,"+
				"product.factory_no,product.product_name,product.specification").
			Joins("left join product on purchase_product.product_id = product.id").
			Preload("FuturesFee").
			Preload("SettlementBill").
			Preload("FinancingFee").
			Preload("TaxFee"). //税款
			Preload("FileInfo").
			Preload("StorageFee").
			Preload("ShippingInfo").
			Preload("PurchaseSales", func(db *gorm.DB) *gorm.DB {
				db = db.Select("purchase_sales.*,customer.name").
					Joins("left join customer ON customer.id = purchase_sales.customer_id")
				return db
			}).
			Find(&bean)

		//清关费用格式化
		var clearanceFeeList []model.ClearanceFee
		err := json.Unmarshal([]byte(bean.ClearanceFee), &clearanceFeeList)
		if err == nil {
			bean.ClearanceFeeList = clearanceFeeList
			bean.ClearanceFee = ""
		}
		return db, bean
	})

}

func purchaseProductDelete(c *gin.Context) {
	sql.HttpDeleteById(c, &model.PurchaseProduct{})
}

func purchaseProductEstimateList(c *gin.Context) {
	sql.HttpHandle(sql.GET, c, func(db *gorm.DB) (*gorm.DB, interface{}) {
		var list []model.PurchaseProduct
		agentId := c.Query("agentId")
		search := c.Query("search")
		status := c.Query("status")
		tx := db.Begin()
		var exchangeRateList []model.ExchangeRate
		if err := tx.Find(&exchangeRateList).Error; err != nil {
			tx.Error = errors.New(sql.ErrorService)
			tx.Callback()
		}

		//基础查询
		tx = tx.
			Select("purchase_product.id,purchase_product.agent_id, purchase_product.container_no," +
				" purchase_product.contract_no,purchase_product.futures_spot,purchase_product.product_price," +
				" purchase_product.inventory_number,purchase_product.inventory_weight, purchase_product.price_unit," +
				" purchase_product.weight_unit,purchase_product.product_number,purchase_product.product_weight," +
				" purchase_product.deposit_status,purchase_product.balance_status,purchase_product.clearance_status," +
				" purchase_product.settlement_total_amount,purchase_product.sales_total_amount," +
				" purchase_product.bill_total_amount,purchase_product.start_date,purchase_product.end_date," +
				" product.factory_no,product.product_name,product.specification,purchase_agent.agent").
			Joins("left join product on purchase_product.product_id = product.id").
			Joins("left join purchase_agent on purchase_product.agent_id = purchase_agent.id")

		//id为空时，查询所有代理的货物信息
		if agentId != "" {
			tx = tx.Where("purchase_product.agent_id = ?", agentId)
		}
		//条件查询
		if search != "" {
			query := "purchase_product.container_no LIKE ? " +
				"OR purchase_product.contract_no LIKE ? " +
				"OR CONCAT(REPLACE(product.factory_no,'.',''),product.product_name) LIKE ?"
			tx = tx.Where(query, "%"+search+"%", "%"+search+"%", "%"+search+"%")
		}
		tx = tx.
			Preload("ShippingInfo"). //港口信息
			Preload("FileInfo", func(db *gorm.DB) *gorm.DB {
				return db.Where("file_info.name LIKE ? OR file_info.name LIKE ?", "%报关单%", "%检疫%").
					Select("name,identification")
			}).
			Preload("PurchaseSales", func(db *gorm.DB) *gorm.DB {
				return db.Select("total_price,sales_number, purchase_product_id")
			}). //出库信息
			Preload("FuturesFee", func(db *gorm.DB) *gorm.DB {
				return db.Where("futures_fee.fee_type = ? OR futures_fee.fee_type = ?", "实际定金", "实际尾款").
					Select("fee_type, purchase_product_id,total_fee")
			}). //费用信息
			Preload("TaxFee", func(db *gorm.DB) *gorm.DB {
				return db.Select("purchase_product_id,total_fee")
			}).
			/*Preload("SettlementBill", func(db *gorm.DB) *gorm.DB {
				return db.Where("settlement_bill.type IN  (?,?,?)", "%定%", "%尾%", "%清%").
					Select("type, purchase_product_id")
			}).
			Preload("BankStatement", func(db *gorm.DB) *gorm.DB {
				db = db.Where("bank_statement.function = ? AND bank_statement.type = ?", "采购", "支出").
					Select("bank_statement.*,bank_account.bank,bank_account.account_name,bank_account.card_number,bank_flow.date").
					Joins("left join bank_account ON bank_statement.account_id = bank_account.id").
					Joins("left join bank_flow ON bank_statement.bank_flow_id = bank_flow.id")
				return db
			}).*/
			Find(&list)

		tx.Commit()
		var result []model.PurchaseProductResult
		for _, product := range list {
			var shippingInfo = product.ShippingInfo
			var bean model.PurchaseProductResult
			bean.Id = product.ID
			bean.Date = product.Date
			bean.AgentId = product.AgentId
			bean.Agent = product.Agent
			bean.ProductName = product.ProductName
			bean.FactoryNo = product.FactoryNo
			bean.ContainerNo = product.ContainerNo
			bean.PriceUnit = product.PriceUnit
			bean.ProductWeight = product.ProductWeight
			bean.ProductNumber = product.ProductNumber
			bean.WeightUnit = product.WeightUnit
			bean.ContractNo = product.ContractNo
			bean.FuturesSpot = product.FuturesSpot
			bean.ProductPrice = product.ProductPrice
			bean.InventoryWeight = product.InventoryWeight
			bean.InventoryNumber = product.InventoryNumber
			bean.Specification = product.Specification
			bean.DepositStatus = product.DepositStatus
			bean.BalanceStatus = product.BalanceStatus
			bean.ClearanceStatus = product.ClearanceStatus
			bean.StartDate = product.StartDate
			bean.EndDate = product.EndDate

			//报关单、检疫
			for _, info := range product.FileInfo {
				if bean.IsDeclaration == false {
					bean.IsDeclaration = strings.Contains(info.Name, "报关单")
				}
				if bean.IsQuarantine == false {
					bean.IsQuarantine = strings.Contains(info.Name, "检疫")
				}
			}

			//船务信息
			if shippingInfo != nil {
				bean.Port = shippingInfo.Port
				bean.ColdStorage = shippingInfo.ColdStorage
				startDate := (time.Time)(shippingInfo.StartDate)
				deliveryDate := (time.Time)(shippingInfo.DeliveryDate)
				arrivalDate := (time.Time)(shippingInfo.ArrivalDate)
				warehousingDate := (time.Time)(shippingInfo.WarehousingDate)
				if !deliveryDate.IsZero() { //已出库
					bean.BillTotalAmount = product.BillTotalAmount
					bean.SettlementTotalAmount = product.SettlementTotalAmount
					bean.SalesTotalAmount = product.SalesTotalAmount
					bean.Profit = math.Round((bean.SalesTotalAmount-bean.BillTotalAmount)*100) / 100
					bean.SalesPrice = math.Round((product.SalesTotalAmount/product.ProductWeight)*100) / 100
					bean.FeeDifference = math.Round((product.SettlementTotalAmount-product.BillTotalAmount)*100) / 100

					bean.ShippingStatus = 6
					bean.ShippingStatusStr = "出库"
					bean.ShippingDate = shippingInfo.DeliveryDate
				} else if !warehousingDate.IsZero() {
					bean.ShippingStatus = 1
					bean.ShippingStatusStr = "入库"
					bean.ShippingDate = shippingInfo.WarehousingDate
				} else if !arrivalDate.IsZero() {
					bean.ShippingStatus = 2
					bean.ShippingStatusStr = "到港"
					bean.ShippingDate = shippingInfo.ArrivalDate
				} else if !startDate.IsZero() {
					bean.ShippingStatus = 3
					bean.ShippingStatusStr = "开船"
					bean.ShippingDate = shippingInfo.StartDate
				} else {
					bean.ShippingStatus = 5
					bean.ShippingStatusStr = "未装船"
				}
			} else {
				bean.ShippingStatus = 5
				bean.ShippingStatusStr = "未装船"
			}

			//人民币盘直接返回单价
			if bean.PriceUnit == "￥" {
				bean.UnitPrice = bean.ProductPrice
			} else if len(product.FuturesFee) == 2 && (bean.ShippingStatus == 1 || bean.ShippingStatus == 2) {
				//美元盘计算单价
				arrivalDate := (time.Time)(shippingInfo.ArrivalDate)
				timeDifferent := int(time.Now().Sub(arrivalDate).Hours() / 24)

				addend := product.FuturesFee[0].TotalFee
				summand := product.FuturesFee[1].TotalFee
				taxAmount := 0.0
				financingAmount := 0.0 //融资
				storageAmount := 0.0   //仓储费

				fmt.Println(product.ContractNo)

				if product.TaxFee != nil {
					taxAmount = product.TaxFee.TotalFee //税款
				} else {
					for _, rate := range exchangeRateList {
						t, err := time.ParseInLocation("2006-01", rate.Date, time.Local)
						if err != nil {
							tx.Error = errors.New("时间解析异常")
							return tx, nil
						}

						if t.Year() != arrivalDate.Year() || t.Month() != arrivalDate.Month() {
							continue
						}
						var rateValue float64
						switch bean.PriceUnit {
						case "$":
							rateValue = rate.Dollar
						case "€":
							rateValue = rate.Euro
						default:
							continue
						}

						taxAmount = math.Round(bean.ProductPrice*bean.ProductWeight*rateValue*0.2208*100) / 100
						break
					}
				}
				productAmount := addend + summand //货款
				clearanceAmount := 8000.0         //清关代理
				if timeDifferent > 0 {
					financingAmount = math.Round((summand)*float64(timeDifferent+10)*0.055/360*100) / 100  //融资
					financingAmount += math.Round(taxAmount*float64(timeDifferent)*0.055/360*100) / 100    //融资
					storageAmount = math.Round(2*bean.ProductWeight/1000*float64(timeDifferent)*100) / 100 //仓储费
				}
				amount := math.Round(productAmount + taxAmount + clearanceAmount + financingAmount + storageAmount)
				bean.UnitPrice = math.Round(amount/product.ProductWeight*100) / 100
				/*fmt.Println(product.ContractNo)
				fmt.Println(taxAmount)
				fmt.Println(timeDifferent)

				fmt.Println(addend)
				fmt.Println(summand)
				fmt.Println(productAmount)
				fmt.Println(clearanceAmount)
				fmt.Println(financingAmount)
				fmt.Println(storageAmount)
				fmt.Println(amount)
				fmt.Println(bean.UnitPrice)
				fmt.Println("------------------")*/
			}

			if status == "库存" && bean.ShippingStatus == 1 {
				result = append(result, bean)
			} else if status == "运输" && (bean.ShippingStatus == 2 || bean.ShippingStatus == 3 || bean.ShippingStatus == 5) {
				result = append(result, bean)
			} else if status == "已售" && bean.ShippingStatus == 6 {
				result = append(result, bean)
			} else if status == "" {
				result = append(result, bean)
			}

		}
		sort.Slice(result, func(i, j int) bool {
			iDate := (time.Time)(result[i].ShippingDate)
			jDate := (time.Time)(result[j].ShippingDate)
			if result[i].ShippingStatus != result[j].ShippingStatus {
				return result[i].ShippingStatus < result[j].ShippingStatus
			}
			if result[i].ShippingStatus == 6 {
				return iDate.After(jDate)
			} else {
				return iDate.Before(jDate)
			}
		})

		return db, result
	})
}

func purchaseProductList(c *gin.Context) {
	sql.HttpHandle(sql.GET, c, func(db *gorm.DB) (*gorm.DB, interface{}) {
		var list []model.PurchaseProduct
		agentId := c.Query("agentId")
		search := c.Query("search")
		status := c.Query("status")
		//基础查询
		db = db.
			Select("purchase_product.id,purchase_product.agent_id, purchase_product.container_no," +
				" purchase_product.contract_no,purchase_product.futures_spot,purchase_product.product_price," +
				" purchase_product.inventory_number,purchase_product.inventory_weight, purchase_product.price_unit," +
				" purchase_product.weight_unit,purchase_product.product_number,purchase_product.product_weight," +
				" purchase_product.deposit_status,purchase_product.balance_status,purchase_product.clearance_status," +
				" purchase_product.settlement_total_amount,purchase_product.sales_total_amount," +
				" purchase_product.bill_total_amount," +
				" product.factory_no,product.product_name,product.specification,purchase_agent.agent").
			Joins("left join product on purchase_product.product_id = product.id").
			Joins("left join purchase_agent on purchase_product.agent_id = purchase_agent.id")

		//id为空时，查询所有代理的货物信息
		if agentId != "" {
			db = db.Where("purchase_product.agent_id = ?", agentId)
		}
		//条件查询
		if search != "" {
			query := "purchase_product.container_no LIKE ? " +
				"OR purchase_product.contract_no LIKE ? " +
				"OR CONCAT(REPLACE(product.factory_no,'.',''),product.product_name) LIKE ?"
			db = db.Where(query, "%"+search+"%", "%"+search+"%", "%"+search+"%")
		}
		db = db.
			Preload("ShippingInfo"). //港口信息
			Preload("FileInfo", func(db *gorm.DB) *gorm.DB {
				return db.Where("file_info.name LIKE ? OR file_info.name LIKE ?", "%报关单%", "%检疫%").
					Select("name,identification")
			}).
			Preload("PurchaseSales", func(db *gorm.DB) *gorm.DB {
				return db.Select("total_price,sales_number, purchase_product_id")
			}). //出库信息
			/*Preload("FuturesFee", applyFeeFilter). //费用信息
			Preload("SettlementBill", func(db *gorm.DB) *gorm.DB {
				return db.Where("settlement_bill.type IN  (?,?,?)", "%定%", "%尾%", "%清%").
					Select("type, purchase_product_id")
			}).
			Preload("BankStatement", func(db *gorm.DB) *gorm.DB {
				db = db.Where("bank_statement.function = ? AND bank_statement.type = ?", "采购", "支出").
					Select("bank_statement.*,bank_account.bank,bank_account.account_name,bank_account.card_number,bank_flow.date").
					Joins("left join bank_account ON bank_statement.account_id = bank_account.id").
					Joins("left join bank_flow ON bank_statement.bank_flow_id = bank_flow.id")
				return db
			}).*/
			Find(&list)

		var result []model.PurchaseProductResult
		for _, product := range list {
			var shippingInfo = product.ShippingInfo
			var bean model.PurchaseProductResult
			bean.Id = product.ID
			bean.Date = product.Date
			bean.AgentId = product.AgentId
			bean.Agent = product.Agent
			bean.ProductName = product.ProductName
			bean.FactoryNo = product.FactoryNo
			bean.ContainerNo = product.ContainerNo
			bean.PriceUnit = product.PriceUnit
			bean.ProductWeight = product.ProductWeight
			bean.ProductNumber = product.ProductNumber
			bean.WeightUnit = product.WeightUnit
			bean.ContractNo = product.ContractNo
			bean.FuturesSpot = product.FuturesSpot
			bean.ProductPrice = product.ProductPrice
			bean.InventoryWeight = product.InventoryWeight
			bean.InventoryNumber = product.InventoryNumber
			bean.Specification = product.Specification
			bean.DepositStatus = product.DepositStatus
			bean.BalanceStatus = product.BalanceStatus
			bean.ClearanceStatus = product.ClearanceStatus
			//报关单、检疫
			for _, info := range product.FileInfo {
				if bean.IsDeclaration == false {
					bean.IsDeclaration = strings.Contains(info.Name, "报关单")
				}
				if bean.IsQuarantine == false {
					bean.IsQuarantine = strings.Contains(info.Name, "检疫")
				}
			}

			//船务信息
			if shippingInfo != nil {
				bean.ColdStorage = shippingInfo.ColdStorage
				startDate := (time.Time)(shippingInfo.StartDate)
				deliveryDate := (time.Time)(shippingInfo.DeliveryDate)
				arrivalDate := (time.Time)(shippingInfo.ArrivalDate)
				warehousingDate := (time.Time)(shippingInfo.WarehousingDate)
				if !deliveryDate.IsZero() { //已出库
					bean.BillTotalAmount = product.BillTotalAmount
					bean.SettlementTotalAmount = product.SettlementTotalAmount
					bean.SalesTotalAmount = product.SalesTotalAmount
					bean.Profit = math.Round((bean.SalesTotalAmount-bean.BillTotalAmount)*100) / 100
					bean.SalesPrice = math.Round((product.SalesTotalAmount/product.ProductWeight)*100) / 100
					bean.FeeDifference = math.Round((product.SettlementTotalAmount-product.BillTotalAmount)*100) / 100

					bean.ShippingStatus = 6
					bean.ShippingStatusStr = "出库"
					bean.ShippingDate = shippingInfo.DeliveryDate
				} else if !warehousingDate.IsZero() {
					bean.ShippingStatus = 1
					bean.ShippingStatusStr = "入库"
					bean.ShippingDate = shippingInfo.WarehousingDate
				} else if !arrivalDate.IsZero() {
					bean.ShippingStatus = 2
					bean.ShippingStatusStr = "到港"
					bean.ShippingDate = shippingInfo.ArrivalDate
				} else if !startDate.IsZero() {
					bean.ShippingStatus = 3
					bean.ShippingStatusStr = "开船"
					bean.ShippingDate = shippingInfo.StartDate
				} else {
					bean.ShippingStatus = 5
					bean.ShippingStatusStr = "未装船"
				}
			} else {
				bean.ShippingStatus = 5
				bean.ShippingStatusStr = "未装船"
			}
			if status == "库存" && bean.ShippingStatus == 1 {
				result = append(result, bean)
			} else if status == "运输" && (bean.ShippingStatus == 2 || bean.ShippingStatus == 3 || bean.ShippingStatus == 5) {
				result = append(result, bean)
			} else if status == "已售" && bean.ShippingStatus == 6 {
				result = append(result, bean)
			} else if status == "" {
				result = append(result, bean)
			}

		}
		sort.Slice(result, func(i, j int) bool {
			iDate := (time.Time)(result[i].ShippingDate)
			jDate := (time.Time)(result[j].ShippingDate)
			if result[i].ShippingStatus != result[j].ShippingStatus {
				return result[i].ShippingStatus < result[j].ShippingStatus
			}
			if result[i].ShippingStatus == 6 {
				return iDate.After(jDate)
			} else {
				return iDate.Before(jDate)
			}
		})

		return db, result
	})
}

/*
*信息修改
 */
func purchaseModify(c *gin.Context) {
	sql.DBHandle(c, sql.UPDATE, func(context *gin.Context, db *gorm.DB) interface{} {
		id := c.PostForm("id")
		db = db.Table("purchase_product").Where("id = ?", id)
		if depositStatus := c.PostForm("depositStatus"); depositStatus != "" {
			db = db.Where("deposit_status != ?", 2).Update("deposit_status", depositStatus)
		}
		if balanceStatus := c.PostForm("balanceStatus"); balanceStatus != "" {
			db = db.Where("balance_status != ?", 2).Update("balance_status", balanceStatus)
		}
		if clearanceStatus := c.PostForm("clearanceStatus"); clearanceStatus != "" {
			db = db.Where("clearance_status != ?", 2).Update("clearance_status", clearanceStatus)
		}
		if feeDifference := c.PostForm("feeDifference"); feeDifference != "" {
			db = db.Update("fee_difference", feeDifference)
		}
		if totalPrice := c.PostForm("billTotalAmount"); totalPrice != "" {
			db = db.Update("bill_total_amount", totalPrice)
		}
		if totalPrice := c.PostForm("settlementTotalAmount"); totalPrice != "" {
			db = db.Update("settlement_total_amount", totalPrice)
		}
		if totalPrice := c.PostForm("salesTotalAmount"); totalPrice != "" {
			db = db.Update("sales_total_amount", totalPrice)
		}
		return "success"
	})
}
